home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / wvnsrc75.zip / WVUSENET.C < prev    next >
C/C++ Source or Header  |  1993-02-08  |  38KB  |  1,469 lines

  1. /* wvusenet.c */
  2. /*  This file consists of the window procedure and support routines
  3.  *  for the main window to the application WinVn.
  4.  */
  5.  
  6. #include "windows.h"
  7.  
  8. #ifndef MAC
  9. #include "winundoc.h"
  10. #include <stdlib.h>
  11. #endif
  12.  
  13. #include "WVglob.h"
  14. #include "WinVn.h"
  15. #ifdef MAC
  16. #include "MRRM1.h"
  17. #include <DialogMgr.h>
  18. #endif
  19.  
  20. #include <stdlib.h>   /* for getenv */
  21.  
  22.  
  23. char newsrc_filename[80];
  24.  
  25. /*--- FUNCTION: WinVnConfWndProc ---------------------------------------
  26.  *
  27.  *    Window procedure for the "Net" window.
  28.  *    This window displays the names of the newsgroups, one per line.
  29.  *
  30.  *    Entry    The usual parameters for any window function.
  31.  *
  32.  *    Note:    We don't do anything until "Initialized" is true.
  33.  *             This way, the user won't try to perform functions
  34.  *             while the communications are still being set up.
  35.  */
  36.  
  37. long FAR PASCAL
  38. WinVnConfWndProc (hWnd, message, wParam, lParam)
  39.      HWND hWnd;
  40.      unsigned message;
  41.      WPARAM wParam;
  42.      LPARAM lParam;
  43. {
  44. #ifndef MAC
  45.   FARPROC lpProcAbout;
  46.   HMENU hMenu;
  47. #endif
  48.   PAINTSTRUCT ps;        /* paint structure          */
  49.   POINT ptCursor;
  50.  
  51.   HDC hDC;            /* handle to display context */
  52.   HWND hWndView;
  53.   HDC hDCView;
  54.   RECT myRect;            /* selection rectangle      */
  55.  
  56.   int j, idoc;
  57.   int found;
  58.   char far *lpsz;
  59.   TypLine far *LinePtr, far * GroupLinePtr;
  60.   TypBlock far *BlockPtr, far * GroupBlockPtr;
  61.   int LinesGone;
  62.   int SelLine;
  63.   HANDLE hBlock;
  64.   TypDoc *MyDoc;
  65.   unsigned int Offset;
  66.  
  67.   int X, Y, nWidth, nHeight;
  68.   int docnum;
  69.   int newdoc;
  70.   char mybuf[MAXINTERNALLINE];
  71.   int mylen;
  72.   int OldSel = FALSE;
  73.   int CtrlState;
  74.   TypLineID MyLineID;
  75.  
  76.   switch (message)
  77.     {
  78. #ifndef MAC
  79.     case WM_SYSCOMMAND:
  80.       if (wParam == ID_ABOUT)
  81.     {
  82.       lpProcAbout = MakeProcInstance (About, hInst);
  83.       DialogBox (hInst, "AboutBox", hWnd, lpProcAbout);
  84.       FreeProcInstance (lpProcAbout);
  85.       break;
  86.     }
  87.       else
  88.     return (DefWindowProc (hWnd, message, wParam, lParam));
  89. #endif
  90.     case WM_CREATE:
  91.       /* Set up the timer which will wake us up every so often
  92.        * so we can check to see if new characters have arrived from
  93.        * the server.
  94.        */
  95.  
  96. #ifndef MAC
  97.       idTimer = SetTimer (hWnd, NULL, 1000, (FARPROC) NULL);
  98.  
  99.       /* Get handle to the hourglass cursor */
  100.  
  101.       hHourGlass = LoadCursor (hInst, IDC_WAIT);
  102.  
  103.       /* Add the "About" option to the system menu.            */
  104.  
  105.       hMenu = GetSystemMenu (hWnd, FALSE);
  106.       ChangeMenu (hMenu, NULL, NULL, NULL, MF_APPEND | MF_SEPARATOR);
  107.       ChangeMenu (hMenu, NULL, "A&bout WinVn...", ID_ABOUT,
  108.           MF_APPEND | MF_STRING);
  109. #endif
  110.       /* Fill in the Net document's window handle that we
  111.        * were unable to fill in in the call to InitDoc.
  112.        */
  113.       NetDoc.hDocWnd = hWnd;
  114.       break;
  115.  
  116.     case WM_CHAR:
  117.       /* Hitting CR on a group name is the same as double-clicking
  118.        * on the name.
  119.        */
  120.       if (!Initializing)
  121.     {
  122.       if (wParam == '\r')
  123.         {
  124. #ifndef MAC
  125.           GetCursorPos (&ptCursor);
  126.           ScreenToClient (hWnd, &ptCursor);
  127.           X = ptCursor.x;
  128.           Y = ptCursor.y;
  129. #else
  130.           GetMouse (&ptCursor);
  131.           X = ptCursor.h;
  132.           Y = ptCursor.v;
  133. #endif
  134.           goto getgroup;
  135.         }
  136.     }
  137.       break;
  138.  
  139.     case WM_KEYDOWN:
  140.       /* See if this key should be mapped to a scrolling event
  141.        * for which we have programmed the mouse.  If so,
  142.        * construct the appropriate mouse call and call the mouse code.
  143.        * Also, F6 means switch to next window.
  144.        * (This latter should also be table-driven.)
  145.        */
  146.       if (!Initializing)
  147.     {
  148.       if (wParam == VK_F6)
  149.         {
  150.           NextWindow (&NetDoc);
  151.         }
  152.       else
  153.         {
  154.           /* Based on the state of the Control key and the value
  155.                * of the key just pressed, look up in the array
  156.                * key2scroll to see if we should process this keystroke
  157.                * as if it were a mouse event.  If so, simulate the
  158.                * mouse event by sending the appropriate message.
  159.                */
  160. #ifndef MAC
  161.           CtrlState = GetKeyState (VK_CONTROL) < 0;
  162.           for (j = 0; j < NUMKEYS; j++)
  163.         {
  164.           if (wParam == key2scroll[j].wVirtKey &&
  165.               CtrlState == key2scroll[j].CtlState)
  166.             {
  167.               SendMessage (hWnd, key2scroll[j].iMessage,
  168.                    key2scroll[j].wRequest, 0L);
  169.               break;
  170.             }
  171.         }
  172. #endif
  173.         }
  174.     }
  175.       break;
  176.  
  177.     case WM_LBUTTONDOWN:
  178.       /*  Clicking the left button on a group name toggles the
  179.        *  selected/not selected status of that group.
  180.        *  Currently selected groups are displayed in reverse video.
  181.        */
  182.       if (!Initializing)
  183.     {
  184.       X = LOWORD (lParam);
  185.       Y = HIWORD (lParam);
  186.  
  187.       if (CursorToTextLine (X, Y, &NetDoc, &BlockPtr, &LinePtr))
  188.         {
  189.           ((TypGroup far *) (((char far *) LinePtr) + sizeof (TypLine)))
  190.         ->Selected ^= TRUE;
  191.           GlobalUnlock (BlockPtr->hCurBlock);
  192.         }
  193.  
  194.       InvalidateRect (hWnd, NULL, FALSE);
  195.     }
  196.       break;
  197.  
  198.     case WM_LBUTTONDBLCLK:
  199.       /*  Double-clicking on a group name creates a "Group"
  200.        *  window, whose purpose is to display the subjects
  201.        *  of the articles in the group.
  202.        */
  203.       if (!Initializing)
  204.     {
  205.       X = LOWORD (lParam);
  206.       Y = HIWORD (lParam);
  207.     getgroup:;
  208.  
  209.       if (CursorToTextLine (X, Y, &NetDoc, &GroupBlockPtr, &GroupLinePtr))
  210.         {
  211.           if (MyDoc = (((TypGroup far *)
  212.         (((char far *) GroupLinePtr) + sizeof (TypLine)))->SubjDoc))
  213.         {
  214.  
  215.           /* We already have a document containing the subjects */
  216.           /* of this group, so just activate it.                */
  217.  
  218.           SetActiveWindow (MyDoc->hDocWnd);
  219.           SetFocus (MyDoc->hDocWnd);
  220.           GlobalUnlock (GroupBlockPtr->hCurBlock);
  221.           break;
  222.         }
  223.           if (CommBusy)
  224.         {
  225.           GlobalUnlock (GroupBlockPtr->hCurBlock);
  226.           MessageBox (hWnd, "Sorry, I am already busy retrieving information from the server.\n\
  227. Try again in a little while.", "Can't request info on group", MB_OK | MB_ICONASTERISK);
  228.           break;
  229.         }
  230.  
  231.           /* At this point, we've determined that the subjects for
  232.                * this newsgroup are not in memory, and that it's OK
  233.                * to fetch them from the server.  (Comm line not busy.)
  234.                * Figure out whether a new window/document should be
  235.                * created for this group & set "newdoc" accordingly.
  236.                */
  237.           newdoc = FALSE;
  238.           if (ViewNew || !ActiveGroupDoc || !(ActiveGroupDoc->InUse))
  239.         {
  240.           found = FALSE;
  241.           for (docnum = 0; docnum < MAXGROUPWNDS; docnum++)
  242.             {
  243.               if (!GroupDocs[docnum].InUse)
  244.             {
  245.               found = TRUE;
  246.               newdoc = TRUE;
  247.               CommDoc = &(GroupDocs[docnum]);
  248.               break;
  249.             }
  250.             }
  251.           if (!found)
  252.             {
  253.               MessageBox (hWnd, "You have too many group windows \
  254. active;\nClose one or select 'Reuse Old Window'.", "Can't open new window", MB_OK | MB_ICONASTERISK);
  255.               UnlockLine (GroupBlockPtr, GroupLinePtr, &hBlock, &Offset, &MyLineID);
  256.               break;
  257.             }
  258.         }
  259.           else
  260.         {
  261.           /* Must reuse old window for this group.           */
  262.           CommDoc = ActiveGroupDoc;
  263.           UnlinkArtsInGroup (CommDoc);
  264.           LockLine (CommDoc->hParentBlock, CommDoc->ParentOffset, CommDoc->ParentLineID, &BlockPtr, &LinePtr);
  265.           ((TypGroup far *)
  266.            (((char far *) LinePtr) + sizeof (TypLine)))->SubjDoc = (TypDoc *) NULL;
  267.           UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  268.           /* clear out contents of this document for reuse */
  269.           FreeDoc (CommDoc);
  270.         }
  271.  
  272.           /* Create window title indicating we are retrieving text. */
  273.  
  274.           CommDoc->InUse = TRUE;
  275.           lpsz = (char far *) (((char far *) GroupLinePtr) +
  276.                    sizeof (TypLine) + sizeof (TypGroup));
  277.           strcpy (mybuf, "Retrieving ");
  278.           lstrcat (mybuf, lpsz);
  279.  
  280.           /* If necessary, create a new window.              */
  281.  
  282.           if (newdoc)
  283.         {
  284.           hWndView = CreateWindow ("WinVnView",
  285.                        mybuf,
  286.                        WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  287.                                    (int) docnum * CharWidth + 1,/* Initial X pos */
  288.                        (int) docnum * LineHeight,
  289.                        (int) xScreen,    /* Initial X Width */
  290.                        (int) (yScreen * 1 / 2),    /* CW_USEDEFAULT, */
  291.                        NULL,
  292.                        NULL,
  293.                        hInst,
  294.                        NULL);
  295.  
  296.           if (!hWndView)
  297.             return (0);    /* ??? */
  298. #ifndef MAC
  299.           ShowWindow (hWndView, SW_SHOWNORMAL);
  300. #endif
  301.         }
  302.           else
  303.         {
  304.           hWndView = CommDoc->hDocWnd;
  305.           SetWindowText (hWndView, mybuf);
  306.         }
  307.           RcvLineCount = 0;
  308.           TimesWndUpdated = 0;
  309.  
  310.           /* Do some housekeeping:  Set group as selected,
  311.                * initialize empty document to hold subject lines,
  312.                * set focus to this document, set pointers linking
  313.                * this document and the subject line.
  314.                */
  315.           ((TypGroup far *) (((char far *) GroupLinePtr) +
  316.                  sizeof (TypLine)))->Selected = TRUE;
  317.           InitDoc (CommDoc, hWndView, &NetDoc, DOCTYPE_GROUP);
  318.           PtrToOffset (GroupBlockPtr, GroupLinePtr, &(CommDoc->hParentBlock),
  319.             &(CommDoc->ParentOffset), &(CommDoc->ParentLineID));
  320.           SetActiveWindow (hWndView);
  321.           SetFocus (hWndView);
  322.  
  323.           ((TypGroup far *) (((char far *) GroupLinePtr) + sizeof (TypLine)))
  324.         ->SubjDoc = CommDoc;
  325.           GlobalUnlock (GroupBlockPtr->hCurBlock);
  326.           InvalidateRect (hWndView, NULL, FALSE);
  327. #ifndef MAC
  328.           UpdateWindow (hWndView);
  329. #endif
  330.           InvalidateRect (NetDoc.hDocWnd, NULL, FALSE);
  331.  
  332.           /* Deal with Comm-related stuff:  set FSA variables,
  333.                * send the GROUP command to NNTP.
  334.                */
  335.  
  336.           CommLinePtr = CommLineIn;
  337.           CommBusy = TRUE;
  338.           CommState = ST_GROUP_RESP;
  339.           hSaveCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  340.           ShowCursor (TRUE);
  341.  
  342. /* capture the mouse to the usenet window, so that we keep the hourglass */
  343.  
  344.           SetCapture (hWnd);
  345.           strcpy (mybuf, "GROUP ");
  346.           lpsz = (char far *) GroupLinePtr + sizeof (TypLine) + sizeof (TypGroup);
  347.           lstrcat (mybuf, lpsz);
  348.           mylstrncpy (CurrentGroup, lpsz, MAXFINDSTRING);
  349.           /* lstrcat(mybuf,"\r"); */
  350.           PutCommLine (mybuf, lstrlen (mybuf));
  351.         }
  352.     }
  353.       break;
  354.  
  355.     case WM_TIMER:
  356.       DoCommInput ();
  357.       break;
  358.  
  359.     case WM_SIZE:
  360.       /* Store the new size of the window.                     */
  361.       GetClientRect (hWnd, &myRect);
  362.       NetDoc.ScXWidth = myRect.right;
  363.       NetDoc.ScYHeight = myRect.bottom;
  364. #ifdef MAC
  365.       NetDoc.ScYLines = (myRect.bottom - myRect.top) / LineHeight;
  366. #else
  367.       NetDoc.ScYLines = (myRect.bottom - myRect.top - TopSpace) / LineHeight;
  368. #endif
  369.       NetDoc.ScXChars = (myRect.right - myRect.left - SideSpace) / CharWidth;
  370.       break;
  371.  
  372.     case WM_VSCROLL:
  373.       if (!Initializing)
  374.     {
  375.       ScrollIt (&NetDoc, wParam, lParam);
  376.     }
  377.       break;
  378.  
  379.     case WM_COMMAND:
  380.       switch (wParam)
  381.     {
  382.  
  383.     case IDM_QUIT:
  384.       SaveNewsrc = FALSE;
  385.     case IDM_EXIT:
  386.       DestroyWindow (hWnd);
  387.       break;
  388.  
  389.     case IDM_VIEW_SEL_GROUP:
  390.       break;
  391.  
  392.     case IDM_SHOW_SUBSCR:
  393.     case IDM_SHOW_ALL_GROUP:
  394.     case IDM_SEL_SUBSCR:
  395.     case IDM_SELECTALL:
  396.       MessageBox (hWnd, "Command not implemented",
  397.               "Sorry", MB_OK);
  398.       break;
  399.  
  400.     case IDM_UNSEL_ALL:
  401.       ForAllLines (&NetDoc, SetLineFlag, 0, FALSE);
  402.       InvalidateRect (hWnd, NULL, FALSE);
  403.       break;
  404.  
  405.     case IDM_SUBSCRIBE:
  406.       InitGroupTable ();
  407.       ForAllLines (&NetDoc, GroupAction, GROUP_ACTION_SUBSCRIBE, TRUE);
  408.       MergeGroups (ADD_SUBSCRIBED_END_OF_SUB);
  409.       CleanUpGroupTable ();
  410.       ForAllLines (&NetDoc, SetLineFlag, 0, FALSE);
  411.       ScreenToTop (&NetDoc);
  412.       InvalidateRect (hWnd, NULL, FALSE);
  413.       break;
  414.  
  415.     case IDM_UNSUBSCRIBE:
  416.       InitGroupTable ();
  417.       ForAllLines (&NetDoc, GroupAction, GROUP_ACTION_UNSUBSCRIBE, FALSE);
  418.       ShellSort ((void far *) NewGroupTable,
  419.                      (size_t) nNewGroups,
  420.                      (size_t) sizeof (void far *),
  421.              GroupCompare);
  422.       MergeGroups (ADD_SUBSCRIBED_END_OF_SUB);
  423.       CleanUpGroupTable ();
  424.       ForAllLines (&NetDoc, SetLineFlag, 0, FALSE);
  425.       ScreenToTop (&NetDoc);
  426.       InvalidateRect (hWnd, NULL, FALSE);
  427.       break;
  428.  
  429.     case IDM_GROUP_TOP:
  430.       InitGroupTable ();
  431.       ForAllLines (&NetDoc, GroupAction, GROUP_ACTION_SUBSCRIBE, TRUE);
  432.       MergeGroups (ADD_SUBSCRIBED_TOP_OF_DOC);
  433.       CleanUpGroupTable ();
  434.       ForAllLines (&NetDoc, SetLineFlag, 0, FALSE);
  435.       ScreenToTop (&NetDoc);
  436.       InvalidateRect (hWnd, NULL, FALSE);
  437.       break;
  438.  
  439.     case IDM_NEW_WIN_GROUP:
  440.       ViewNew = !ViewNew;
  441.       CheckView (hWnd);
  442.       break;
  443.  
  444.     case IDM_NEW_WIN_ARTICLE:
  445.       NewArticleWindow = !NewArticleWindow;
  446.       CheckView (hWnd);
  447.       break;
  448.  
  449.     case IDM_COMMOPTIONS:
  450. #ifndef MAC
  451.       if (DialogBox (hInst, "WinVnComm", hWnd, lpfnWinVnCommDlg))
  452.         {
  453.           InvalidateRect (hWnd, NULL, TRUE);
  454.         }
  455. #endif
  456.  
  457.       break;
  458.  
  459.     case IDM_CONFIG_PERSONAL:
  460. #ifndef MAC
  461.       DialogBox (hInst, "WinVnPersonal", hWnd, lpfnWinVnPersonalInfoDlg);
  462. #endif
  463.       break;
  464.  
  465.     case IDM_CONFIG_MISC:
  466. #ifndef MAC
  467.       DialogBox (hInst, "WinVnMisc", hWnd, lpfnWinVnMiscDlg);
  468. #endif
  469.       break;
  470.  
  471.     case IDM_RESET:
  472.       CommBusy = FALSE;
  473.       CommState = ST_NONE;
  474.       break;
  475.  
  476.     case IDM_FIND:
  477.       FindDoc = &NetDoc;
  478. #ifndef MAC
  479.       if (DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg))
  480.         {
  481.           found = DoFind (TRUE);
  482.           if (!found)
  483.         {
  484.           strcpy (mybuf, "\"");
  485.           strcat (mybuf, NetDoc.SearchStr);
  486.           strcat (mybuf, "\" not found.");
  487.           MessageBox (hWnd, mybuf, "Not found", MB_OK);
  488.         }
  489.         }
  490. #else
  491.       {
  492.         DialogPtr myDialog;
  493.         BOOL dialogDone = FALSE, oktofind = FALSE;
  494.         int itemhit;
  495.         int itemType;
  496.         Handle itemHandle;
  497.         Rect itemRect;
  498.         char myStr[255];
  499.  
  500.         myDialog = GetNewDialog (DLOG_FIND, NULL, (WindowPtr) - 1);
  501.         GetDItem (myDialog, 3, &itemType, &itemHandle, &itemRect);
  502.         strcpy (myStr, FindDoc->SearchStr);
  503.         CtoPstr (myStr);
  504.         SetIText (itemHandle, myStr);
  505.         ShowWindow ((WindowPtr) myDialog);
  506.         while (!dialogDone)
  507.           {
  508.         ModalDialog (NULL, &itemhit);
  509.         switch (itemhit)
  510.           {
  511.           case OK:
  512.             dialogDone = TRUE;
  513.             oktofind = TRUE;
  514.             break;
  515.           case Cancel:
  516.             dialogDone = TRUE;
  517.             break;
  518.           }
  519.           }
  520.         HideWindow (myDialog);
  521.         if (oktofind)
  522.           {
  523.         GetIText (itemHandle, &myStr);
  524.         PtoCstr (myStr);
  525.         strcpy (FindDoc->SearchStr, (char *) myStr);
  526.         found = DoFind (TRUE);
  527.         if (!found)
  528.           {
  529.             strcpy (mybuf, "\"");
  530.             strcat (mybuf, NetDoc.SearchStr);
  531.             strcat (mybuf, "\" not found.");
  532.             MessageBox (hWnd, mybuf, "Not found", MB_OK);
  533.           }
  534.           }
  535.       }
  536. #endif
  537.       break;
  538.  
  539.     case IDM_FIND_NEXT_SAME:
  540.       FindDoc = &NetDoc;
  541.       if (strcmp (FindDoc->SearchStr, ""))
  542.         {
  543.           found = DoFind (FALSE);
  544.           if (!found)
  545.         {
  546.           strcpy (mybuf, "\"");
  547.           strcat (mybuf, NetDoc.SearchStr);
  548.           strcat (mybuf, "\" not found.");
  549.           MessageBox (hWnd, mybuf, "No more occurrences", MB_OK);
  550.         }
  551.         }
  552.       break;
  553. #ifndef MAC
  554.     case ID_ABOUT:
  555.       lpProcAbout = MakeProcInstance (About, hInst);
  556.       DialogBox (hInst, "AboutBox", hWnd, lpProcAbout);
  557.       FreeProcInstance (lpProcAbout);
  558.       break;
  559.  
  560.     case IDM_HELP:
  561.       MakeHelpPathName (mybuf, MAXINTERNALLINE);
  562.       WinHelp (hWndConf, mybuf, HELP_INDEX, 0L);
  563.       break;
  564. #endif
  565.  
  566.     case IDM_MAIL:
  567.       CreatePostingWnd ((TypDoc *) NULL, DOCTYPE_MAIL);
  568.       break;
  569.     }
  570.       break;
  571.  
  572.     case WM_PAINT:
  573.       {
  574.     HANDLE hBlock;
  575.     unsigned int Offset, MyLen, width, indicatorwidth;
  576.     int VertLines, HorzChars;
  577.     int EndofDoc = FALSE;
  578.     int RangeHigh, CurPos;
  579.     int RestX, Xtext;
  580.     char far *textptr;
  581.     char *cptr, *cptr2;
  582.     char indicator;
  583.     char indcptr[128];
  584.           char group_name[MAXINTERNALLINE];
  585.     char init_msg[60];
  586.     TypGroup far *MyGroup;
  587.     HANDLE hBlackBrush;
  588.     DWORD MyColors[4], MyBack[4];
  589.     DWORD Rop;
  590.     RECT myRect;
  591.     POINT myPoint;
  592.     SIZE string_size;
  593.     int MyColorMask = 1, PrevColorMask = MyColorMask;
  594. #define SUBSCR_MASK 1
  595. #define SELECT_MASK 2
  596.  
  597.     hDC = BeginPaint (hWnd, &ps);
  598.     GetClientRect (hWnd, &myRect);
  599.     SelectObject (hDC, hFont);
  600.  
  601.     /* If still initializing comm link, put out a message    */
  602.     /* to that effect.                                       */
  603.  
  604.     switch (Initializing)
  605.       {
  606.       case INIT_ESTAB_CONN:
  607.         cptr = "Establishing link";
  608.         cptr2 = "to news server...";
  609.  
  610.         goto display_msg;
  611.  
  612.       case INIT_READING_NEWSRC:
  613.         cptr = "Reading your log";
  614.         cptr2 = "(\"newsrc\")...";
  615.         goto display_msg;
  616.  
  617.       case INIT_SCANNING_NETDOC:
  618.         cptr = "Creating hash table";
  619.         cptr2 = "from current groups...";
  620.         goto display_msg;
  621.  
  622.       case INIT_GETTING_LIST:
  623.         sprintf (mybuf, "Receiving %uth newsgroup", RcvLineCount);
  624.         cptr = mybuf;
  625.         cptr2 = "name from server...";
  626.  
  627.       display_msg:;
  628.         X = SideSpace + CharWidth;
  629.         Y = StartPen + 2 * LineHeight;
  630.         strcpy (init_msg, cptr);
  631.         strcat (init_msg, "    ");
  632.         j = strlen (init_msg);
  633.         TextOut (hDC, X, Y, init_msg, j);
  634.         strcpy (init_msg, cptr2);
  635.         strcat (init_msg, "    ");
  636.         j = strlen (init_msg);
  637.         TextOut (hDC, X, Y + LineHeight, init_msg, j);
  638.         break;
  639.  
  640.  
  641.       case INIT_DONE:
  642.  
  643.         VertLines = NetDoc.ScYLines;
  644.         HorzChars = NetDoc.ScXChars;
  645. #ifndef MAC
  646.         MyColors[0] = NetUnSubscribedColor;
  647.         MyColors[1] = GetTextColor (hDC);
  648.         MyColors[2] = MyColors[0];
  649.         MyColors[3] = GetBkColor (hDC);
  650.  
  651.         MyBack[0] = MyColors[3];
  652.         MyBack[1] = MyBack[0];
  653.         MyBack[2] = MyColors[1];
  654.         MyBack[3] = MyBack[2];
  655.  
  656.         GetTextExtentPoint (hDC, "*", 2, &string_size);
  657.         indicatorwidth = string_size.cx * 7 / 7;
  658.  
  659. #endif
  660.         LockLine (NetDoc.hCurTopScBlock, NetDoc.TopScOffset, NetDoc.TopScLineID,
  661.               &BlockPtr, &LinePtr);
  662.  
  663.         /* Update the scroll bar thumb position.                 */
  664.  
  665.         CurPos = NetDoc.TopLineOrd;
  666.         if (CurPos < 0)
  667.           CurPos = 0;
  668.         RangeHigh = NetDoc.TotalLines - VertLines;
  669.         if (RangeHigh < 0)
  670.           RangeHigh = 0;
  671.         SetScrollRange (hWnd, SB_VERT, 0, RangeHigh, FALSE);
  672.         SetScrollPos (hWnd, SB_VERT, CurPos, TRUE);
  673. #ifdef MAC
  674.         myRect.right = NetDoc.DocClipRect.right;
  675.         myRect.top = 0;
  676.         myRect.bottom = LineHeight;
  677. #endif
  678.  
  679.         /* Loop through the lines, painting them on the screen. */
  680.  
  681.         X = SideSpace;
  682.         Xtext = X + indicatorwidth;
  683.         Y = StartPen;
  684.         if (LinePtr->length != END_OF_BLOCK)
  685.           do
  686.         {
  687.           MyGroup = ((TypGroup far *)
  688.                  ((char far *) LinePtr + sizeof (TypLine)));
  689.           MyLen = MyGroup->NameLen;
  690.           textptr = (char far *) LinePtr + sizeof (TypLine) +
  691.             sizeof (TypGroup);
  692.  
  693.           /* Figure out the color of this line.                 */
  694.  
  695.           if (MyGroup->Subscribed)
  696.             {
  697.               MyColorMask |= SUBSCR_MASK;
  698.             }
  699.           else
  700.             {
  701.               MyColorMask &= (0xff - SUBSCR_MASK);
  702.             }
  703.           if (MyGroup->Selected)
  704.             {
  705.               MyColorMask |= SELECT_MASK;
  706.               Rop = BLACKNESS;
  707.             }
  708.           else
  709.             {
  710.               MyColorMask &= 0xff - SELECT_MASK;
  711.               Rop = WHITENESS;
  712.             }
  713.           if (MyColorMask != PrevColorMask)
  714.             {
  715.               SetTextColor (hDC, MyColors[MyColorMask]);
  716.               SetBkColor (hDC, MyBack[MyColorMask]);
  717.               PrevColorMask = MyColorMask;
  718.             }
  719.  
  720.           /* Figure out what indicator character to use. */
  721.  
  722.           indicator = ' ';
  723.           if (NetDoc.FindLineID == LinePtr->LineID)
  724.             {
  725.               indicator = '>';
  726.             }
  727.           else if (MyGroup->HighestPrevSeen)
  728.             {
  729.               if (MyGroup->ServerLast > MyGroup->HighestPrevSeen)
  730.             {
  731.               indicator = '*';
  732.             }
  733.             }
  734.  
  735.           mylstrncpy (group_name, textptr, MyGroup->NameLen + 1);
  736.  
  737.           sprintf (indcptr, "%c %5ld %s ",
  738.                                indicator,
  739.                                    (long) MyGroup->ServerEstNum,
  740.                                group_name);
  741.  
  742.           /* Now write out the line.                            */
  743.  
  744. /*          TextOut (hDC, X, Y, indcptr, 4); */
  745.  
  746.           MyLen = strlen (indcptr);
  747.           GetTextExtentPoint (hDC, indcptr, MyLen,&string_size);
  748.           width = string_size.cx;
  749.           TextOut (hDC, X, Y, indcptr, MyLen);
  750. #if 0
  751.           if (MyLen < HorzChars)
  752.             {
  753. #endif
  754. #ifdef MAC
  755.               GetPen (&myPoint);
  756.               myRect.left = myPoint.h;
  757.               FillRect (&myRect, white);
  758.  
  759.               myRect.top += LineHeight;
  760.               myRect.bottom += LineHeight;
  761. #else
  762.               RestX = X + width;
  763.               PatBlt (hDC, RestX, Y, myRect.right - RestX, LineHeight, Rop);
  764. #endif
  765. #if 0
  766.             }
  767. #endif
  768.           Y += LineHeight;
  769.         }
  770.           while (--VertLines > 0 && NextLine (&BlockPtr, &LinePtr));
  771.  
  772.         SetTextColor (hDC, MyColors[1]);
  773.         SetBkColor (hDC, MyBack[1]);
  774.  
  775.         /* Blank out bottom and top of screen */
  776.         PatBlt (hDC, 0, Y, myRect.right, myRect.bottom - Y, PATCOPY);
  777.         PatBlt (hDC, 0, 0, myRect.right, TopSpace, PATCOPY);
  778.  
  779.         UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  780.       }
  781.     EndPaint (hWnd, &ps);
  782.     break;
  783.       }
  784.  
  785.     case WM_ENDSESSION:
  786. #ifndef MAC
  787.       WinHelp (hWndConf, LFN_HELP, HELP_QUIT, 0L);
  788. #endif
  789.       break;
  790.  
  791.     case WM_DESTROY:
  792.       for (idoc = 0; idoc < MAXGROUPWNDS; idoc++)
  793.     {
  794.       if (GroupDocs[idoc].InUse)
  795.         {
  796.           UpdateSeenArts (&(GroupDocs[idoc]));
  797.         }
  798.     }
  799.       if (SaveNewsrc)
  800.     {
  801.       WriteNewsrc ();
  802.     }
  803.       MRRCloseComm ();
  804. #if 0
  805.       SendMessage (hDosWnd, WM_KEYDOWN, 0x5a, 0x2c0001L);
  806.       SendMessage (hDosWnd, WM_CHAR, 0x1a, 0x2c0001L);
  807.       SendMessage (hDosWnd, WM_KEYDOWN, 0xd, 0x1c0001L);
  808.       SendMessage (hDosWnd, WM_CHAR, 0xd, 0x1c0001L);
  809. #endif
  810.       PostQuitMessage (0);
  811.       break;
  812.  
  813.     default:
  814.       return (DefWindowProc (hWnd, message, wParam, lParam));
  815.     }
  816.   return (0);
  817. }
  818.  
  819. #ifndef MAC
  820. /*---  FUNCTION: About ---------------------------------------------------
  821.  *
  822.  *  Process messages for "About" dialog box
  823.  */
  824.  
  825. BOOL FAR PASCAL 
  826. About (hDlg, message, wParam, lParam)
  827.      HWND hDlg;
  828.      unsigned message;
  829.      WORD wParam;
  830.      LONG lParam;
  831. {
  832.   switch (message)
  833.     {
  834.     case WM_INITDIALOG:
  835.       return (TRUE);
  836.  
  837.     case WM_COMMAND:
  838.       if (wParam == IDOK)
  839.     {
  840.       EndDialog (hDlg, TRUE);
  841.       return (TRUE);
  842.     }
  843.       break;
  844.     }
  845.   return (FALSE);
  846. }
  847.  
  848. #endif
  849.  
  850. /* Function CheckView -----------------------------
  851.  *
  852.  *  This function handles checking and unchecking menu items.
  853.  *
  854.  *    Entry    hWnd     is the window whose menu is to be altered.
  855.  *                      Currently works only for the Net window.
  856.  *
  857.  *    Exit     The appropriate items on the menu have been checked or
  858.  *             unchecked.
  859.  */
  860.  
  861. VOID 
  862. CheckView (hWnd)
  863.      HWND hWnd;
  864. {
  865.   WORD MenuItemToCheck, MenuItemToUncheck;
  866.   HMENU hMenu;
  867.   int CheckIt;
  868.  
  869.   if (ViewNew)
  870.     {
  871.       CheckIt = MF_CHECKED | MF_BYCOMMAND;
  872.     }
  873.   else
  874.     {
  875.       CheckIt = MF_UNCHECKED | MF_BYCOMMAND;
  876.     }
  877. #ifdef MAC
  878.   hMenu = gOptionsMenu;
  879. #else
  880.   hMenu = GetMenu (hWnd);
  881. #endif
  882.   CheckMenuItem (hMenu, IDM_NEW_WIN_GROUP, CheckIt);
  883.  
  884.   if (NewArticleWindow)
  885.     {
  886.       CheckIt = MF_CHECKED | MF_BYCOMMAND;
  887.     }
  888.   else
  889.     {
  890.       CheckIt = MF_UNCHECKED | MF_BYCOMMAND;
  891.     }
  892.   CheckMenuItem (hMenu, IDM_NEW_WIN_ARTICLE, CheckIt);
  893. }
  894.  
  895. /* --- function CrackGroupLine --------------------------------------
  896.  *
  897.  *  Given a line from a .newsrc file, create a text line containing
  898.  *  a structure of type TypGroup containing the same information.
  899.  *  The line is zero-terminated upon input.
  900.  *
  901.  *    Entry    buf      points to a zero-terminated line from .newsrc.
  902.  *             lineptr  points to a place to put the converted textline.
  903.  *
  904.  *    Exit     The line pointed to by "lineptr" now is a TypLine textline
  905.  *             containing a structure of type TypGroup, containing the
  906.  *             information in the input line from .newsrc.
  907.  *
  908.  *  Returns TRUE iff group was subscribed to.
  909.  */
  910. BOOL
  911. CrackGroupLine (buf, lineptr)
  912.      char *buf;
  913.      TypLine *lineptr;
  914. {
  915.   char *grname = (char *) lineptr + sizeof (TypLine) + sizeof (TypGroup);
  916.   TypGroup *group = (TypGroup *) ((char *) lineptr + sizeof (TypLine));
  917.   TypRange *RangePtr;
  918.   BOOL MoreNums;
  919.   unsigned int MyLength;
  920.  
  921.   group->Subscribed = FALSE;
  922.   group->Selected = FALSE;
  923.   group->NameLen = 0;
  924.   group->SubjDoc = (TypDoc *) NULL;
  925.   group->ServerEstNum = 0;
  926.   group->ServerFirst = 0;
  927.   group->ServerLast = 0;
  928.   group->HighestPrevSeen = 0;
  929.   group->nRanges = 0;
  930.   group->header_handle = (HANDLE) NULL;
  931.  
  932.   /* Copy group name to output line.                               */
  933.  
  934.   while (*buf && *buf != ':' && *buf != '!')
  935.     {
  936.       *(grname++) = *(buf++);
  937.       (group->NameLen)++;
  938.     }
  939.   *(grname++) = '\0';
  940.  
  941.   if (!(*buf))
  942.     {
  943.       /* Ran off end of line without seeing ':' or '!'.  Error.      */
  944.     }
  945.   else
  946.     {
  947.       if (*buf == ':')
  948.     {
  949.       group->Subscribed = TRUE;
  950.     }
  951.       buf++;
  952.     }
  953.  
  954.   /* Look for the highest article number previously seen, in an
  955.    * entry of form "s" followed by a number.
  956.    */
  957.  
  958.   while (*buf && *buf == ' ')
  959.     buf++;
  960.   if (*buf == 's')
  961.     {
  962.       buf++;
  963.       GetNum (&buf, &(group->HighestPrevSeen));
  964.     }
  965.  
  966.   /* Convert the article number ranges to the internal numeric
  967.    * form we use in WinVN.
  968.    */
  969.  
  970.   RangePtr = (TypRange *) ((char *) lineptr + sizeof (TypLine) +
  971.                RangeOffset (group->NameLen));
  972.  
  973.   RangePtr->Last = RangePtr->First = 0;
  974.  
  975.   MoreNums = TRUE;
  976.   while (MoreNums)
  977.     {
  978.       while (*buf && (*buf == ' ' || *buf == ','))
  979.     buf++;
  980.       if (GetNum (&buf, &(RangePtr->First)))
  981.     {
  982.       /* We have the first number in a range.                     */
  983.       (group->nRanges)++;
  984.       RangePtr->Last = RangePtr->First;
  985.       if (*buf == '-')
  986.         {
  987.           buf++;
  988.           if (GetNum (&buf, &(RangePtr->Last)))
  989.         {
  990.           RangePtr++;
  991.           /* at this point, we are positioned just after a range */
  992.         }
  993.           else
  994.         {
  995.           RangePtr->Last = RangePtr->First;
  996.           MoreNums = FALSE;
  997.         }
  998.         }
  999.       else if (*buf == ',')
  1000.         {
  1001.           /* We have a single number "n"; interpret as the range "n-n".
  1002.                */
  1003.           RangePtr++;
  1004.         }
  1005.       else
  1006.         {
  1007.           /* That must have been the last number.                  */
  1008.           MoreNums = FALSE;
  1009.         }
  1010.     }
  1011.       else
  1012.     {
  1013.       MoreNums = FALSE;
  1014.     }
  1015.     }
  1016.   if (group->nRanges == 0)
  1017.     (group->nRanges)++;
  1018.  
  1019.   MyLength = sizeof (TypLine) + RangeOffset (group->NameLen) +
  1020.     sizeof (TypRange) * (group->nRanges) + sizeof (int);
  1021.  
  1022.   lineptr->length = MyLength;
  1023.   lineptr->LineID = NextLineID++;
  1024.   *(int *) ((char *) lineptr + MyLength - sizeof (int)) = MyLength;
  1025.  
  1026.   return (group->Subscribed);
  1027. }
  1028.  
  1029. /*-- function CursorToTextLine ----------------------------------------
  1030.  *
  1031.  *   Routine to locate a text line in a document, based on the
  1032.  *   cursor position.  Used to figure out which line is being selected
  1033.  *   when a user clicks a mouse button.
  1034.  *
  1035.  *   Entry    X, Y    are the position of the cursor.
  1036.  *            DocPtr  points to the current document.
  1037.  *
  1038.  *   Exit     *LinePtr points to the current line, if one was found.
  1039.  *            *BlockPtr points to the current block, if found.
  1040.  *            Function returns TRUE iff a line was found that corresponds
  1041.  *              to the cursor position.
  1042.  */
  1043. BOOL
  1044. CursorToTextLine (X, Y, DocPtr, BlockPtr, LinePtr)
  1045.      int X;
  1046.      int Y;
  1047.      TypDoc *DocPtr;
  1048.      TypBlock far **BlockPtr;
  1049.      TypLine far **LinePtr;
  1050. {
  1051.   int found;
  1052.   int SelLine;
  1053.  
  1054.   if (Y < TopSpace || Y > TopSpace + DocPtr->ScYLines * LineHeight ||
  1055.       X < SideSpace)
  1056.     {
  1057.       /* Cursor is in no-man's-land at edge of window.               */
  1058.       found = FALSE;
  1059.     }
  1060.   else
  1061.     {
  1062.       found = TRUE;
  1063.       SelLine = (Y - TopSpace) / LineHeight;
  1064.  
  1065.       LockLine (DocPtr->hCurTopScBlock, DocPtr->TopScOffset, DocPtr->TopScLineID,
  1066.         BlockPtr, LinePtr);
  1067.  
  1068.       for (found = TRUE, il = 0; il < SelLine; il++)
  1069.     {
  1070.       if (!NextLine (BlockPtr, LinePtr))
  1071.         {
  1072.           found = FALSE;    /* ran off end of document */
  1073.           break;
  1074.         }
  1075.     }
  1076.     }
  1077.   return (found);
  1078. }
  1079.  
  1080. /*-- function ReadNewsrc ----------------------------------------------
  1081.  *
  1082.  *    Reads NEWSRC into the Net document.
  1083.  *    This routine opens NEWSRC, reads & parses the lines into the NetDoc
  1084.  *    document, and closes the file.  One call does it all.
  1085.  *
  1086.  *    Entry    The NetDoc document is assumed to be initialized.
  1087.  *
  1088.  *    Exit     Returns TRUE if all went well, else zero.
  1089.  */
  1090. int
  1091. ReadNewsrc ()
  1092. {
  1093.   TypBlock far *BlockPtr;
  1094.   TypLine *LocalLinePtr, far * GroupPtr;
  1095.   HANDLE hLine;
  1096.   HANDLE hBlock;
  1097.   HANDLE hRetCode;
  1098.   unsigned int Offset;
  1099.   TypLineID MyLineID;
  1100.   char mes[60];
  1101.   char far *chptr;
  1102.   int mylen, j;
  1103. #define  TEMPBUFSIZE   1240
  1104.   char mybuf[TEMPBUFSIZE];
  1105.   char *grname;
  1106.   TypMRRFile *MRRFile;
  1107.   int returned;
  1108.   char * env_var;
  1109.  
  1110.   LockLine (NetDoc.hCurAddBlock, NetDoc.AddOffset, NetDoc.AddLineID, &BlockPtr, &GroupPtr);
  1111.   NetDoc.hDocWnd = hWndConf;
  1112.  
  1113.   hLine = LocalAlloc (LMEM_MOVEABLE, TEMPBUFSIZE);
  1114.   LocalLinePtr = (TypLine *) LocalLock (hLine);
  1115.  
  1116.   env_var = getenv ("WINVN");        /* get path to winvn.ini */
  1117.   if (lstrlen (env_var))
  1118.    {
  1119.      lstrcpy (newsrc_filename, env_var);
  1120.      if (*(newsrc_filename + lstrlen (newsrc_filename) - 1) == '\\')
  1121.        lstrcat (newsrc_filename, "newsrc");
  1122.      else
  1123.        lstrcat (newsrc_filename, "\\newsrc");
  1124.    }
  1125.   else
  1126.    {
  1127.      MessageBox (hWndConf,"Environment variable WINVN not set.","Fatal Error", MB_OK | MB_ICONEXCLAMATION);
  1128.      return (0);
  1129.    }
  1130.  
  1131.   hRetCode = MRROpenFile (newsrc_filename, 0, OF_READ, &MRRFile);
  1132.   if ((int) hRetCode <= 0)
  1133.     {
  1134.       return FALSE;
  1135. #if 0
  1136.       sprintf (mes, "Unable to open the NEWSRC file; code=%d", (int) hRetCode);
  1137.       MessageBox (hWndConf, mes, mybuf, MB_OK);
  1138. #endif
  1139.     }
  1140.   else
  1141.     {
  1142.       /* Loop to read lines, convert them to internal format, and
  1143.        * insert them into the NetDoc document.
  1144.        */
  1145.  
  1146.       while ((returned = MRRReadLine (MRRFile, mybuf, TEMPBUFSIZE)) > (-1))
  1147.     {
  1148.       mybuf[returned] = '\0';
  1149.       if (CrackGroupLine (mybuf, LocalLinePtr))
  1150.         {
  1151.           NetDoc.ActiveLines++;
  1152.         }
  1153.       AddLine (LocalLinePtr, &BlockPtr, &GroupPtr);
  1154.     }
  1155.       MRRCloseFile (MRRFile);
  1156.     }
  1157.  
  1158.   /* Change the title of the Net document.  I suppose that,
  1159.    * strictly speaking, this oughtn't be done in this routine.
  1160.    */
  1161.   SetNetDocTitle ();
  1162.   UnlockLine (BlockPtr, GroupPtr, &hBlock, &Offset, &MyLineID);
  1163.  
  1164.   NetDoc.hCurTopScBlock = NetDoc.hFirstBlock;
  1165.   NetDoc.TopScOffset = sizeof (TypBlock);
  1166.   NetDoc.TopScLineID = 0L;
  1167.  
  1168.   return (TRUE);
  1169. }
  1170.  
  1171. char *ltoa ();
  1172.  
  1173. /*--- function WriteNewsrc ---------------------------------------------
  1174.  *
  1175.  *  Write out a NEWSRC file, based on the information in the
  1176.  *  NetDoc document.  Use the standard Unix "rn" format for .newsrc.
  1177.  *
  1178.  *    Entry    no parameters
  1179.  *             NetDoc   has the group information.
  1180.  *
  1181.  *    Exit     The NEWSRC file has been written.
  1182.  */
  1183. void
  1184. WriteNewsrc ()
  1185. {
  1186.   TypBlock far *BlockPtr;
  1187.   TypLine far *LinePtr;
  1188.   HANDLE hLine;
  1189.   HANDLE hBlock;
  1190.   unsigned int Offset;
  1191.   TypLineID MyLineID;
  1192.   char mes[60], mybuf[60];
  1193.   char far *fromptr;
  1194.   char *toptr;
  1195.   char *NewsLine;
  1196.   HANDLE hRetCode;
  1197.   TypMRRFile *MRRFile;
  1198.   int returned;
  1199.   int nranges, nchars;
  1200.   TypGroup far *Group;
  1201.   TypRange far *RangePtr;
  1202.   BOOL firstrange;
  1203.  
  1204.   LockLine (NetDoc.hFirstBlock, sizeof (TypBlock), 0L, &BlockPtr, &LinePtr);
  1205.  
  1206.   hLine = LocalAlloc (LMEM_MOVEABLE, BLOCK_SIZE);
  1207.   NewsLine = (char *) LocalLock (hLine);
  1208.  
  1209. /*   strcpy (mybuf, "newsrc"); */
  1210.   hRetCode = MRROpenFile (newsrc_filename, 0, OF_CREATE && OF_WRITE, &MRRFile);
  1211.   if ((int) hRetCode < 0)
  1212.     {
  1213.       sprintf (mes, "MRROpenFile returned %d", hRetCode);
  1214.       MessageBox (hWndConf, mes, mybuf, MB_OK);
  1215.     }
  1216.   else
  1217.     {
  1218.       do
  1219.     {
  1220.       toptr = NewsLine;
  1221.       Group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
  1222.  
  1223.           if (Group->ServerFirst != 0) {
  1224.       /* Copy group name                                          */
  1225.       fromptr = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypGroup);
  1226.       while (*(toptr++) = *(fromptr++));
  1227.       toptr--;
  1228.  
  1229.       /* Affix : or ! depending upon whether subscribed.          */
  1230.       *(toptr++) = (char) (Group->Subscribed ? ':' : '!');
  1231.       *(toptr++) = ' ';
  1232.  
  1233.       /* If we know the highest article number on the server,
  1234.            * output it preceded by an "s".
  1235.            */
  1236.       if (Group->ServerLast)
  1237.         {
  1238.           *(toptr++) = 's';
  1239.           ltoa ((unsigned long) Group->ServerLast, toptr, 10);
  1240.           while (*toptr)
  1241.         toptr++;
  1242.           *(toptr++) = ' ';
  1243.         }
  1244.  
  1245.       /* Affix ranges of articles read.                          */
  1246.       firstrange = TRUE;
  1247.       nranges = Group->nRanges;
  1248.       RangePtr = (TypRange far *) ((char far *) Group + RangeOffset (Group->NameLen));
  1249.  
  1250.       while ((nranges--) > 0)
  1251.         {
  1252.           /* Write out ',' if not first range of articles.         */
  1253.  
  1254.           if (!firstrange)
  1255.         {
  1256.           *(toptr++) = ',';
  1257.         }
  1258.           else
  1259.         {
  1260.           firstrange = FALSE;
  1261.         }
  1262.           /* Write out first article in a range.                   */
  1263.  
  1264.           ltoa ((unsigned long) RangePtr->First, toptr, 10);
  1265.           while (*toptr)
  1266.         toptr++;
  1267.  
  1268.           /* If the range is of form "n-n", just put out "n"       */
  1269.  
  1270.           if (RangePtr->First != RangePtr->Last)
  1271.         {
  1272.           /* Put out the hyphen in middle of range.                */
  1273.           *(toptr++) = '-';
  1274.           /* Put out the last article in a range.                  */
  1275.           ltoa ((unsigned long) RangePtr->Last, toptr, 10);
  1276.           while (*toptr)
  1277.             toptr++;
  1278.         }
  1279.           RangePtr++;
  1280.         }
  1281.       MRRWriteLine (MRRFile, NewsLine, toptr - NewsLine);
  1282.           }
  1283.     }
  1284.       while (NextLine (&BlockPtr, &LinePtr));
  1285.       UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  1286.       MRRCloseFile (MRRFile);
  1287.     }
  1288. }
  1289.  
  1290. /*--- function SetNetDocTitle -------------------------------------------
  1291.  *
  1292.  */
  1293. void
  1294. SetNetDocTitle ()
  1295. {
  1296.   char mybuf[120];
  1297.  
  1298.   sprintf (mybuf, "WinVN:  %d groups; %d subscribed", NetDoc.TotalLines,
  1299.        NetDoc.ActiveLines);
  1300.   SetWindowText (hWndConf, mybuf);
  1301.  
  1302. }
  1303.  
  1304. /*--- function SetLineFlag --------------------------------------------
  1305.  *
  1306.  *  Set some flag in a line in a document.
  1307.  *
  1308.  *  Entry   Doc      points to the document.
  1309.  *          LinePtr  points to th line.
  1310.  *
  1311.  *  Exit    lFlag    says what to do.
  1312.  */
  1313. void
  1314. SetLineFlag (TypDoc * Doc, TypBlock far ** BlockPtr, TypLine far ** LinePtr, int wFlag, int wValue)
  1315. {
  1316.   switch (wFlag)
  1317.     {
  1318.       case LINE_FLAG_SET:
  1319.       ((TypGroup far *) (((char far *) *LinePtr) + sizeof (TypLine)))
  1320.       ->Selected = wValue;
  1321.       break;
  1322.     }
  1323. }
  1324.  
  1325.  
  1326. /*--- function GroupAction --------------------------------------------
  1327.  *
  1328.  *  Perform some action on a group that is specified by a pointer
  1329.  *  to a line in the Net document.
  1330.  *  Typically called for each line in the Net document by
  1331.  *  ForAllLines.
  1332.  *
  1333.  *  Entry   Doc      points to NetDoc
  1334.  *          LinePtr  points to a line in that document.
  1335.  *          lFlag    indicates what to do with that line.
  1336.  */
  1337. void
  1338. GroupAction (TypDoc * Doc, TypBlock far ** BlockPtr, TypLine far ** LinePtr, int wFlag, int wValue)
  1339. {
  1340.  
  1341.   switch (wFlag)
  1342.     {
  1343.       case GROUP_ACTION_SUBSCRIBE:
  1344.       case GROUP_ACTION_UNSUBSCRIBE:
  1345.       if (((TypGroup far *) (((char far *) *LinePtr) + sizeof (TypLine)))
  1346.       ->Selected)
  1347.     {
  1348.       ((TypGroup far *) (((char far *) *LinePtr) + sizeof (TypLine)))
  1349.       ->Subscribed = wValue;
  1350.       AddGroupToTable ((char far *) *LinePtr);
  1351.       DeleteLine (BlockPtr, LinePtr);
  1352.     }
  1353.       break;
  1354.  
  1355.     }
  1356. }
  1357.  
  1358. /****************************************************************************
  1359.  
  1360.    FUNCTION:   MakeHelpPathName
  1361.  
  1362.    PURPOSE:    HelpEx assumes that the .HLP help file is in the same
  1363.                directory as the HelpEx executable.This function derives
  1364.                the full path name of the help file from the path of the
  1365.                executable.
  1366.  
  1367.    Taken from HELPEX.C, from the MS Windows SDK.
  1368.  
  1369. ****************************************************************************/
  1370.  
  1371. void 
  1372. MakeHelpPathName (szFileName, maxchars)
  1373.      char *szFileName;
  1374.      int maxchars;
  1375. {
  1376.   char *pcFileName;
  1377.   int nFileNameLen;
  1378.  
  1379.   nFileNameLen = GetModuleFileName (hInst, szFileName, maxchars);
  1380.   pcFileName = szFileName + nFileNameLen;
  1381.  
  1382.   while (pcFileName > szFileName)
  1383.     {
  1384.       if (*pcFileName == '\\' || *pcFileName == ':')
  1385.     {
  1386.       *(++pcFileName) = '\0';
  1387.       break;
  1388.     }
  1389.       nFileNameLen--;
  1390.       pcFileName--;
  1391.     }
  1392.  
  1393.   if ((nFileNameLen + 13) < maxchars)
  1394.     {
  1395.       lstrcat (szFileName, LFN_HELP);
  1396.     }
  1397.  
  1398.   else
  1399.     {
  1400.       lstrcat (szFileName, "?");
  1401.     }
  1402.  
  1403.   return;
  1404. }
  1405.  
  1406.  
  1407. int
  1408. cursor_to_char_number (X, Y, DocPtr, BlockPtr, LinePtr)
  1409.      int X;
  1410.      int Y;
  1411.      TypDoc *DocPtr;
  1412.      TypBlock far **BlockPtr;
  1413.      TypLine far **LinePtr;
  1414. {
  1415.   int SelLine;
  1416.   int charnum = -1;
  1417.   int extent;
  1418.   char mybuf[10];
  1419.   char far * textptr;
  1420.   int textlen;
  1421.   HDC display_context;
  1422.   SIZE string_size;
  1423.  
  1424.   if (Y < TopSpace || Y > TopSpace + DocPtr->ScYLines * LineHeight ||
  1425.       X < SideSpace)
  1426.     {
  1427.     return (-1);
  1428.     }
  1429.   else
  1430.     {
  1431.       SelLine = (Y - TopSpace) / ArtLineHeight;
  1432.  
  1433.       LockLine (DocPtr->hCurTopScBlock, DocPtr->TopScOffset, DocPtr->TopScLineID,
  1434.         BlockPtr, LinePtr);
  1435.  
  1436.       for (il = 0; il < SelLine; il++)
  1437.     {
  1438.       if (!NextLine (BlockPtr, LinePtr))
  1439.         {
  1440.           return (-1);
  1441.           break;
  1442.         }
  1443.     }
  1444.     }
  1445.  
  1446. /* find the right character on the text line */
  1447.   textlen = ((TypText far *) ((char far *) (*LinePtr) +
  1448.                               sizeof (TypLine)))->NameLen;
  1449.  
  1450.  
  1451.   if (textlen) {
  1452.     textptr = (char far *) ((char far *) (*LinePtr) + sizeof (TypLine) + sizeof (TypText) );
  1453.     display_context = GetDC (DocPtr->hDocWnd);
  1454.  
  1455.     for (charnum = 1; charnum < textlen; charnum++)
  1456.       {
  1457.           GetTextExtentPoint (display_context, (LPSTR) textptr, charnum,&string_size);
  1458.         extent = string_size.cx;
  1459.         if (extent > (X - SideSpace)) break;
  1460.       }
  1461.     ReleaseDC (DocPtr->hDocWnd, display_context);
  1462.     return (charnum - 1);
  1463.   }
  1464.  
  1465. }
  1466.  
  1467.  
  1468. /* Last line of WVUSENET.C */
  1469.